﻿using System.Diagnostics;
using KinonekoSoftware.Foundation.Platform;

#if AVALONIA

namespace KinonekoSoftware.Platform
{

    using Avalonia;
    using Avalonia.Platform.Storage;
    using Avalonia.Controls.ApplicationLifetimes;
    using DryIoc;

    public abstract partial class NativeApplication : Application, IStorageService, ITopLevelProvider
    {
        public static readonly FilePickerFileType Music = new FilePickerFileType("All Music")
        {
            Patterns = new string[]
            {
                "*.mp3",
                "*.wav",
                "*.ogg",
                "*.flac",
            },
            AppleUniformTypeIdentifiers = new string[]
            {
                "public.mp3",
                "com.microsoft.waveform-audio",
            },
            MimeTypes = new string[]
            {
                "audio/*",
            },
        };

        public static readonly FilePickerFileType Video = new FilePickerFileType("All Video")
        {
            Patterns = new string[]
            {
                "*.mpeg",
                "*.avi",
                "*.mp4",
            },
            AppleUniformTypeIdentifiers = new string[]
            {
                "public.mpeg",
                "public.mpeg-4",
            },
            MimeTypes = new string[]
            {
                "video/*",
            },
        };

        /// <summary>
        /// 初始化生命周期
        /// </summary>
        protected Control SetupLifetime()
        {
            //
            // 创建MainView
            var mainView = CreateMainView();


            //
            // 设置Shell
            if (mainView.DataContext is not ShellCore)
            {
                mainView.DataContext = Ioc.Get<ShellCore>();
            }

#if MACOS || LINUX
            //
            // macOS 或者 Linux 框架，使用IClassicDesktopStyleApplicationLifetime
            //
            // 创建Window并赋值。
            //

            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime classic)
            {
                classic.MainWindow = mainView;
            }
            
            //
            //
            ((ITopLevelProvider)this).TopLevel = TopLevel.GetTopLevel(mainView);
            
            //
            //
            return mainView;
#else

            //
            // iOS 或者 Android 框架，ISingleViewApplicationLifetime
            //
            // 创建Control并赋值。
            //
            if (ApplicationLifetime is ISingleViewApplicationLifetime spa)
            {
                spa.MainView = mainView;
            }


            //
            // 尝试设置TopLevel，但是有可能失败。
            // 如果失败，则需要在MainWindow的Loaded事件中获取。
            ((ITopLevelProvider)this).TopLevel = TopLevel.GetTopLevel(mainView);

            return mainView;
#endif
        }

        /// <summary>
        /// 创建Shell
        /// </summary>
        /// <returns>返回Shell</returns>
        protected abstract ShellCore CreateShell();


        /// <summary>
        /// 初始化Shell
        /// </summary>
        /// <returns>返回Shell</returns>
        protected ShellCore SetupShell()
        {
            ShellCore shell;

            if (!Ioc.IsRegistered<ShellCore>())
            {

                //
                // 安装Shell
                shell = CreateShell();
                Ioc.Use<ShellCore>(shell);
                Ioc.Container
                   .UseInstance(
                                shell.GetType(),
                                shell,
                                IfAlreadyRegistered.AppendNewImplementation);
                Ioc.UseInstance<IViewService, IViewServiceAmbient>(shell);
            }
            else
            {
                //
                // 启动
                shell = Ioc.Get<ShellCore>();
            }

            return shell;
        }

        /// <summary>
        /// 
        /// </summary>
        public sealed override void OnFrameworkInitializationCompleted()
        {
            //
            //
            var context = SynchronizationContext.Current!;
            var shell   = SetupShell();



            Xplat.SetupUIThread(context);

            //
            // 安装存储服务，提供
            Ioc.Use<IStorageService>(this);

            //
            //
            var mainView = SetupLifetime();

            //
            //
            base.OnFrameworkInitializationCompleted();

            //
            //
            OnFrameworkInitializationCompletedOverride();


            //
            //
            ((ITopLevelProvider)this).TopLevel = TopLevel.GetTopLevel(mainView);

            //
            // 启动
            shell.Start();
        }


        protected virtual void OnFrameworkInitializationCompletedOverride()
        {

        }

        static FilePickerOpenOptions GetOptions(FileFormat format, bool allowMultiple = false)
        {
            var types = format switch
            {
                FileFormat.Image => FilePickerFileTypes.ImageAll,
                FileFormat.Music => Music,
                FileFormat.Video => Video,
                FileFormat.Html  => FilePickerFileTypes.TextPlain,
                FileFormat.Pdf   => FilePickerFileTypes.Pdf,
                FileFormat.All   => FilePickerFileTypes.All,
                _                => FilePickerFileTypes.ImagePng,
            };

            var options = new FilePickerOpenOptions
            {
                AllowMultiple = allowMultiple,
                FileTypeFilter = new[]
                {
                    types,
                },
            };

            return options;
        }


        public async Task<Result<IOResult>> SingleFile(FileFormat format)
        {
            var toplevelProvider = ((ITopLevelProvider)this);
            var toplevel         = toplevelProvider.TopLevel;
            var storage          = toplevel.StorageProvider;

            var items = await storage.OpenFilePickerAsync(GetOptions(format));

            if (items is null || items.Count == 0)
            {
                return Result<IOResult>.Failed(string.Empty);
            }

            var item = items[0];

            if (item is null)
            {
                return Result<IOResult>.Failed(string.Empty);
            }

            try
            {
                var stream = await item.OpenReadAsync();
                var buffer = new byte[stream.Length];


                Debug.Assert(stream.Length > 0);
                Debug.Assert(stream.Length < int.MaxValue);

                var len = await stream.ReadAsync(buffer);

                //
                //
                Debug.Assert(stream.Length == len);


                var result = new IOResult
                {
                    Buffer    = buffer,
                    Name      = item.Name,
                    Path      = item.Path.AbsolutePath,
                    Extension = Path.GetExtension(item.Name),
                };

                return Result<IOResult>.Success(result);

            }
            catch(Exception ex)
            {
                return Result<IOResult>.Failed(ex.Message);
            }
        }


        public async Task<Result<IList<IOResult>>> MultiFile(FileFormat format)
        {
            var toplevelProvider = ((ITopLevelProvider)this);
            var toplevel         = toplevelProvider.TopLevel;
            var storage          = toplevel.StorageProvider;

            var items = await storage.OpenFilePickerAsync(GetOptions(format));

            if (items is null || items.Count == 0)
            {
                return Result<IList<IOResult>>.Failed(string.Empty);
            }

            try
            {
                var list = new List<IOResult>(4);

                foreach (var item in items)
                {
                    var stream = await item.OpenReadAsync();
                    var buffer = new byte[stream.Length];


                    Debug.Assert(stream.Length > 0);
                    Debug.Assert(stream.Length < int.MaxValue);

                    var len = await stream.ReadAsync(buffer);

                    //
                    //
                    Debug.Assert(stream.Length == len);


                    var result = new IOResult
                    {
                        Buffer    = buffer,
                        Name      = item.Name,
                        Path      = item.Path.AbsolutePath,
                        Extension = Path.GetExtension(item.Name),
                    };


                    //
                    //
                    list.Add(result);
                }



                return Result<IList<IOResult>>.Success(list);

            }
            catch(Exception ex)
            {
                return Result<IList<IOResult>>.Failed(ex.Message);
            }
        }


        TopLevel ITopLevelProvider.TopLevel { get; set; }
    }
}

#endif